package com.behome.netty.common.util;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class ClassKit {
    public ClassKit() {
    }

    public static <T> Set<Class<T>> getAllClassFromPkg(Class<T> baseClazz, String... pkgNames) {
        Set<Class<T>> returnClazzSet = null;
        if(baseClazz != null) {
            if(pkgNames != null && pkgNames.length != 0) {
                returnClazzSet = new HashSet<>();
                String[] var10 = pkgNames;
                int var11 = pkgNames.length;
                for(int var12 = 0; var12 < var11; ++var12) {
                    String pkgName = var10[var12];
                    Set<Class> allClass = getClassesByPkgName(pkgName);
                    if(allClass != null) {
                        for (Class classes : allClass) {
                            if (baseClazz.isAssignableFrom(classes) && !baseClazz.equals(classes)) {
                                returnClazzSet.add(classes);
                            }
                        }
                    }
                }
            } else {
                String packageName = baseClazz.getPackage().getName();
                Set<Class> allClass = getClassesByPkgName(packageName);
                if(allClass != null) {
                    returnClazzSet = new HashSet<>();
                    for (Class clazz : allClass) {
                        if (baseClazz.isAssignableFrom(clazz) && !baseClazz.equals(clazz)) {
                            returnClazzSet.add(clazz);
                        }
                    }
                }
            }
        }

        return returnClazzSet;
    }

    public static Set<Class> getClassesByPkgName(String pkgName) {
        Set<Class> classes = new HashSet();
        boolean recursive = true;
        String packageDirName = pkgName.replace('.', '/');

        try {
            Enumeration<URL> dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);

            while(true) {
                label67:
                while(dirs.hasMoreElements()) {
                    URL url = (URL)dirs.nextElement();
                    String protocol = url.getProtocol();
                    if("file".equals(protocol)) {
                        String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
                        findAndAddClassesInPackageByFile(pkgName, filePath, recursive, classes);
                    } else if("jar".equals(protocol)) {
                        try {
                            JarFile jar = ((JarURLConnection)url.openConnection()).getJarFile();
                            Enumeration<JarEntry> entries = jar.entries();

                            while(true) {
                                JarEntry entry;
                                String name;
                                int idx;
                                do {
                                    if (!entries.hasMoreElements()) {
                                        continue label67;
                                    }
                                    entry = entries.nextElement();
                                    name = entry.getName();
                                    if (name.charAt(0) == 47) {
                                        name = name.substring(1);
                                    }
                                } while (!name.startsWith(packageDirName));

                                idx = name.lastIndexOf(47);
                                if(idx != -1) {
                                    pkgName = name.substring(0, idx).replace('/', '.');
                                }
                                if(name.endsWith(".class") && !entry.isDirectory()) {
                                    String className = name.substring(pkgName.length() + 1, name.length() - 6);
                                    try {
                                        classes.add(Class.forName(pkgName + '.' + className));
                                    } catch (ClassNotFoundException var14) {
                                        var14.printStackTrace();
                                    }
                                }
                            }
                        } catch (IOException var15) {
                            var15.printStackTrace();
                        }
                    }
                }

                return classes;
            }
        } catch (IOException var16) {
            var16.printStackTrace();
            return classes;
        }
    }

    public static void findAndAddClassesInPackageByFile(String packageName, String packagePath, final boolean recursive, Set<Class> classes) {
        File dir = new File(packagePath);
        if(dir.exists() && dir.isDirectory()) {
            File[] dirfiles = dir.listFiles(file -> recursive && file.isDirectory() || file.getName().endsWith(".class"));
            File[] var6 = dirfiles;
            int var7 = dirfiles.length;
            for(int var8 = 0; var8 < var7; ++var8) {
                File file = var6[var8];
                if(file.isDirectory()) {
                    findAndAddClassesInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), recursive, classes);
                } else {
                    String className = file.getName().substring(0, file.getName().length() - 6);
                    try {
                        classes.add(Class.forName(packageName + '.' + className));
                    } catch (ClassNotFoundException var12) {
                        var12.printStackTrace();
                    }
                }
            }

        }
    }
}
